import numpy as np
import pandas as pd
from plotnine import *Pandas 사용 팁
Pandas에서 유용하게 사용할 수 있는 여러가지 메소드들을 알아보자!
해당 포스트는 전북대학교 통계학과 최규빈 교수님의 강의내용을 토대로 재구성되었음을 알립니다.
1. 라이브러리 imports
2. pabdas : transform column
A. lambda
B. map
C. s.apply(변환함수) | 원소들을 각각 변환
- 변환함수 : 원래 형식을 보존하면서 원소들을 바꾸는 함수
- 집계함수 : 벡터 -> 스칼라 (평균을 불러주는 함수 : [1,2,3,4,5] -> 3)
라고 하자.
df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv') ## DataFrame
s = df.Height ## Seriess0 189cm
1 179cm
2 172cm
3 181cm
4 172cm
...
17655 190cm
17656 195cm
17657 190cm
17658 187cm
17659 186cm
Name: Height, Length: 17660, dtype: object
뒤에 cm가 붙어있는 범주형 자료로 저장되어있음.
s.apply(lambda x : int(x[:3])) ## 집계함수가 아닌 변환함수만 적용할 수 있음. 각 원소에 함수 적용.
##s.apply(lambda x : x[:3]).apply(int) ## 연쇄적으로
##s.apply(lambda x : x[:3]).astype('int64') ## astype() 이용0 189
1 179
2 172
3 181
4 172
...
17655 190
17656 195
17657 190
17658 187
17659 186
Name: Height, Length: 17660, dtype: int64
cm를 제거하고 포맷을 정수형으로 변경하였다.
### D. s.str, idx.str | string 오브젝트에만 사용할 수 있는 함수를 사용
df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv')
s = df.Height"180cm"[:3]'180'
'180cm'.replace('cm','')'180'
위와 같은 연산을 시리즈에 적용시키고 싶다.
s.str[:3]
##s.str.replace('cm', '') ## 개별 문자열과 동일하게 메소드를 적용시켜도 된다.0 189
1 179
2 172
3 181
4 172
...
17655 190
17656 195
17657 190
17658 187
17659 186
Name: Height, Length: 17660, dtype: object
문자열의 메소드를 그대로 적용 가능
- 예시2 : 원소별로 isupper를 수행(대문자인지 판별)
_s = pd.Series(['A','B','C','d','e','F'])
_s0 A
1 B
2 C
3 d
4 e
5 F
dtype: object
_s.str.isupper()0 True
1 True
2 True
3 False
4 False
5 True
dtype: bool
- 예시3 : 원소별로 공백 제거(pd.Serise 뿐만 아니라 pd.index 자료형에도 사용가능)
df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv')
idx = df.columnsidx.str.replace(' ', '')Index(['ID', 'Name', 'Age', 'Photo', 'Nationality', 'Flag', 'Overall',
'Potential', 'Club', 'ClubLogo', 'Value', 'Wage', 'Special',
'PreferredFoot', 'InternationalReputation', 'WeakFoot', 'SkillMoves',
'WorkRate', 'BodyType', 'RealFace', 'Position', 'Joined', 'LoanedFrom',
'ContractValidUntil', 'Height', 'Weight', 'ReleaseClause', 'KitNumber',
'BestOverallRating'],
dtype='object')
- 쉽게 말해서 string데이터를 지닌 개체에 string에 사용할 수 있는 메소드를 사용할 수 있도록 하는 게 pandas의 str이라고 보면 된다.
E. s.astype() | 조건을 충족한 시리즈의 타입을 변경
- 예시1 : 원소의 타입을 변경
s = pd.Series(list('12345'))
s0 1
1 2
2 3
3 4
4 5
dtype: object
s.astype(int)
##s.apply(int)0 1
1 2
2 3
3 4
4 5
dtype: int64
- 예시2 : 원소의 타입을 변환한 이후 브로드캐스팅
s1 = pd.Series(list('12345'))
s2 = pd.Series([-1,-2,-3,-4,-5])s1+s2TypeError: ignored
Error : 형식이 달라 불가능
s1.astype(int) + s20 0
1 0
2 0
3 0
4 0
dtype: int64
s2.astype(str) + s10 -11
1 -22
2 -33
3 -44
4 -55
dtype: object
- 예시3 : 원소의 타입을 변환한 이후 브로드캐스팅(str)
df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | logFare | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S | 1.981001 |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C | 4.266662 |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S | 2.070022 |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S | 3.972177 |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S | 2.085672 |
위의 자료에서 Embarked열과 Pclass열을 사용하여 아래와 같은 New Feature를 만들어라.
| Embarked | Pclass | New Feature |
|---|---|---|
| ‘S’ | 3 | ‘S3’ |
| ‘C’ | 1 | ‘C1’ |
| ‘S’ | 3 | ‘S3’ |
| ‘S’ | 1 | ‘S1’ |
| ‘S’ | 3 | ‘S3’ |
둘다 문자열이면 단순히 +를 이용해 브로드캐스팅하면 되지만, 타입이 달라 불가하다.
df.Embarked + df.Pclass.apply(str)
##df.Embarked + df.Pclass.astype(str)
##df.Embarked + pd.Series(list(map(lambda x : str(x)), df.Pclass))0 S3
1 C1
2 S3
3 S1
4 S3
dtype: object
### F. 컴프리헨션, lambda + map을 무시하지 말 것
- 예시1
df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | logFare | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S | 1.981001 |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C | 4.266662 |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S | 2.070022 |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S | 3.972177 |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S | 2.085672 |
위 자료에서 아래와 같은 변환을 하고 싶다면 apply만으로 사용하기에 부담이 된다.
\[ f(\text{sex}, \text{sibsp}) = \begin{cases} 0.7 + 0.25 \times \text{sibsp} & \text{if } \text{sex} = \text{'female'} \\ 0.2 + 0.15 \times \text{sibsp} & \text{otherwise} \end{cases} \]
list(map(lambda sex, sibsp : 0.7+0.25*sibsp if sex == 'female' else 0.2+0.15*sibsp, df.Sex, df.SibSp))[0.35, 0.95, 0.7, 0.95, 0.2]
df.assign(Probablity = list(map(lambda sex, sibsp : 0.7+0.25*sibsp if sex == 'female' else 0.2+0.15*sibsp, df.Sex, df.SibSp)))| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | logFare | Probablity | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S | 1.981001 | 0.35 |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C | 4.266662 | 0.95 |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S | 2.070022 | 0.70 |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S | 3.972177 | 0.95 |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S | 2.085672 | 0.20 |
- 예시2
df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df| PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | logFare | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S | 1.981001 |
| 1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C | 4.266662 |
| 2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S | 2.070022 |
| 3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S | 3.972177 |
| 4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S | 2.085672 |
위의 자료에서 Name열을 아래와 같이 분리하는 작업을 수행하라.
| title | Name | |
|---|---|---|
| 0 | Mr | Owen Harris Braund |
| 1 | Mrs | John Bradley (Florence Briggs Thayer) Cumings |
| 2 | Miss | Laina Heikkinen |
| 3 | Mrs | Jacques Heath (Lily May Peel) Futrelle |
| 4 | Mr | William Henry Allen |
- 풀이 1
df.Name.str.replace(', ','/').str.replace('. ','/').str.split('/')0 [Braund, Mr, Owen Harris]
1 [Cumings, Mrs, John Bradley (Florence Briggs T...
2 [Heikkinen, Miss, Laina]
3 [Futrelle, Mrs, Jacques Heath (Lily May Peel)]
4 [Allen, Mr, William Henry]
Name: Name, dtype: object
[[title, name + ' ' + f_name] for f_name, title, name in df.Name.str.replace(', ','/').str.replace('. ','/').str.split('/')][['Mr', 'Owen Harris Braund'],
['Mrs', 'John Bradley (Florence Briggs Thayer) Cumings'],
['Miss', 'Laina Heikkinen'],
['Mrs', 'Jacques Heath (Lily May Peel) Futrelle'],
['Mr', 'William Henry Allen']]
- 풀이 2 : 이중 컴프리헨션이 될까 해서 해봤는데… 되네?~(솔직히 안될 이유가 없긴 함, 리스트를 반환하는 거니까…)~
[[names[0], names[1] + ' ' + f_name] for f_name, names in [[f_name, names.split('. ')] for f_name, names in df.Name.str.split(', ')]][['Mr', 'Owen Harris Braund'],
['Mrs', 'John Bradley (Florence Briggs Thayer) Cumings'],
['Miss', 'Laina Heikkinen'],
['Mrs', 'Jacques Heath (Lily May Peel) Futrelle'],
['Mr', 'William Henry Allen']]
lists = [[names[0], names[1] + ' ' + f_name] for f_name, names in [[f_name, names.split('. ')] for f_name, names in df.Name.str.split(', ')]]
pd.DataFrame({'title' : np.array(lists)[:,0], 'Name' : np.array(lists)[:,1]})| title | Name | |
|---|---|---|
| 0 | Mr | Owen Harris Braund |
| 1 | Mrs | John Bradley (Florence Briggs Thayer) Cumings |
| 2 | Miss | Laina Heikkinen |
| 3 | Mrs | Jacques Heath (Lily May Peel) Futrelle |
| 4 | Mr | William Henry Allen |